#include "rw_lock.h"

void RWLock::acquiredRead() {
    std::unique_lock<std::mutex> lock(mtx_);
    // 没有线程在写的时候开始读
    cvRead_.wait(lock, [this]() { return !writing_.load(); });
    ++readerCount_;
}

void RWLock::releaseRead() {
    std::unique_lock<std::mutex> lock(mtx_);
    // 读计数自减 1，若计数为 0，则通知其他的读写线程
    if (--readerCount_ == 0) {
        cvRead_.notify_all();
        cvWrite_.notify_all();
    }
}

void RWLock::acquiredWrite() {
    std::unique_lock<std::mutex> lock(mtx_);
    // 没有线程在写或读计数为 0，开始读
    cvWrite_.wait(lock,
                  [this]() { return !writing_.load() && (readerCount_ == 0); });
}

void RWLock::releaseWrite() {
    std::unique_lock<std::mutex> lock(mtx_);
    // 释放写之后，通知其他的读写线程
    writing_.store(false);
    cvRead_.notify_all();
    cvWrite_.notify_all();
}

namespace anotherWay {
void RWLock::rlock() {
    std::unique_lock<std::mutex> ul(mtx_);
    if (status_ < 0) {
        ++readBlockedCnt_;
        cvRead_.wait(ul, [&]() -> bool {
            return writeBlockedCnt_ == 0 && status_ >= 0;
        });
        --readBlockedCnt_;
    }
    ++status_;
}

void RWLock::wlock() {
    std::unique_lock<std::mutex> ul(mtx_);
    if (status_ != 0) {
        ++writeBlockedCnt_;
        cvWrite_.wait(ul, [&]() -> bool { return status_ == 0; });
        --writeBlockedCnt_;
    }
    status_ = -1;
}

void RWLock::unlock() {
    std::lock_guard<std::mutex> lg(mtx_);
    if (status_ < 0) {
        status_ = 0;
    } else if (status_ > 0) {
        --status_;
    } else {  // status_ == 0 invalid call
        return;
    }

    if (status_ == 0) {
        if (writeBlockedCnt_ > 0) {
            cvWrite_.notify_one();
        } else if (readBlockedCnt_ > 0) {
            cvRead_.notify_all();
        }
    }
}

}  // namespace anotherWay